home *** CD-ROM | disk | FTP | other *** search
- #define DEBUG
-
- #include <Traps.h>
- #include <GenericPatch.h>
- #include <OSUtils.h>
- #include <stddef.h>
- #include <Extension.h>
- #include <Utils.h>
- #include <Exceptions.h>
- #include "Patches.h"
- #include <LoMem2.h>
-
- // <menus.h>
-
- Point Mouse : 0x830;
-
- static PostEventPatch *thePostEventPatch;
- static ButtonPatch *theButtonPatch;
- static GetMousePatch *theGetMousePatch;
- static EventAvailPatch *theEventAvailPatch;
-
- static short theMenuSelect;
- static Rect theMenuBarRect;
-
- static short _max(short a, short b)
- {
- if (a > b)
- return a;
-
- return b;
- }
-
- static Boolean IsTimely(long lastTime)
- {
- return (Ticks - (DoubleTime >> 1)) <= lastTime;
- }
-
- static Boolean IsAround(Point p1, Point p2)
- {
- Rect r1, r2, rToss;
-
- r1.top = p1.v - 2;
- r1.bottom = p1.v + 2;
- r1.left = p1.h - 2;
- r1.right = p1.h + 2;
-
- r2.top = p2.v - 2;
- r2.bottom = p2.v + 2;
- r2.left = p2.h - 2;
- r2.right = p2.h + 2;
-
- return SectRect(&r1, &r2, &rToss);
- }
-
- static Boolean MouseInMenubar()
- {
- return PtInRect(Mouse, &theMenuBarRect);
- }
-
- #define cEsc 0x1b
- #define cPeriod 0x2e
- #define cEnter 0x03
- #define cReturn 0x0d
- #define cTab 0x09
-
- #define cUpArrow 0x1e
- #define cDownArrow 0x1f
- #define cLeftArrow 0x1c
- #define cRightArrow 0x1d
- #define cSpace 0x20
-
- #define CMDKEY ((Keys1 & 0x00008000) != 0)
- #define OPTKEY ((Keys1 & 0x00000004) != 0)
- #define SFTKEY ((Keys1 & 0x00000001) != 0)
- #define CTLKEY ((Keys1 & 0x00000008) != 0)
-
- static void ProcessKeyDown(short c)
- {
- switch (c & 0x00ff) {
- case cPeriod:
- if (! CMDKEY)
- break;
- // else, fall through
-
- case cEsc:
- theEventAvailPatch->SetStickyEvent(eStopBad);
- break;
-
- case cEnter:
- case cReturn:
- if (! CTLKEY)
- theEventAvailPatch->SetStickyEvent(eStopGood);
- break;
-
- case cTab:
- if (! SFTKEY)
- theEventAvailPatch->SetStickyEvent(eNextMenu);
- else
- theEventAvailPatch->SetStickyEvent(ePrevMenu);
- break;
-
- case cRightArrow:
- if (CMDKEY)
- theEventAvailPatch->SetStickyEvent(eLastMenu);
- else
- theEventAvailPatch->SetStickyEvent(eNextMenu);
- break;
-
- case cLeftArrow:
- if (CMDKEY)
- theEventAvailPatch->SetStickyEvent(eFirstMenu);
- else
- theEventAvailPatch->SetStickyEvent(ePrevMenu);
- break;
-
- case cUpArrow:
- theEventAvailPatch->SetStickyEvent(ePrevItem);
- break;
-
- case cSpace:
- case cDownArrow:
- theEventAvailPatch->SetStickyEvent(eNextItem);
- break;
- }
- }
-
- /******************************************************************************************/
-
- ButtonPatch::ButtonPatch()
- {
- GenericPatch::InitGenericPatch(_Button, offsetof(ButtonPatchParms, itsResult));
- Install();
- Switch(ePatchOff);
- }
-
- void ButtonPatch::Behavior()
- {
- reg ButtonPatchParms *parms = (ButtonPatchParms *) itsFrame->parameters;
- parms->itsResult = -1;
- AbortTrap();
- }
-
- /******************************************************************************************/
-
- PostEventPatch::PostEventPatch()
- {
- GenericPatch::InitGenericPatch(_PostEvent, 0);
- Install();
- itsClick = eInitialClick;
- }
-
- long PostEventPatch::FakeNavigation()
- {
- Point zeroPt;
- itsClick = eSecondClick;
- theEventAvailPatch->SetupNavigation();
- theButtonPatch->Switch(ePatchOn);
- return MenuSelect(Mouse);
- }
-
- void PostEventPatch::Behavior()
- {
- Switch(ePatchOff);
-
- switch ((short) itsFrame->ra0) {
- case mouseUp:
- if ((itsClick == eFirstMouseUp)
- && IsAround(Mouse, itsLastMouse)
- && IsTimely(itsLastTime)
- && ((theMenuSelect > 0) || MouseInMenubar())) {
- theButtonPatch->Switch(ePatchOn);
- AbortTrap();
- itsFrame->rd0 = noErr;
- itsClick = eSecondClick;
- } else {
- itsClick = eInitialClick;
- }
- itsLastMouse = Mouse;
- break;
-
- case mouseDown:
- if (itsClick == eInitialClick)
- itsClick = eFirstMouseUp;
- else if (itsClick == eSecondClick) {
- AbortTrap();
- itsFrame->rd0 = noErr;
- theButtonPatch->Switch(ePatchOff);
- itsClick = eInitialClick;
- }
- itsLastTime = Ticks;
- itsLastMouse = Mouse;
- break;
-
- case keyDown:
- if (itsClick == eSecondClick) {
- ProcessKeyDown(itsFrame->rd0 & 0xffff);
- AbortTrap();
- }
- break;
- }
-
- Switch(ePatchOn);
- }
-
- /******************************************************************************************/
-
- MenuSelectPatch::MenuSelectPatch()
- {
- GenericPatch::InitGenericPatch(_MenuSelect, offsetof(MenuSelectParameters, itsResult));
- Install();
- }
-
- void MenuSelectPatch::Behavior()
- {
- #if 0
- reg MenuSelectParameters* params = (MenuSelectParameters*)itsFrame->parameters;
- reg MenuSelectProcPtr oldMenuSelect = (MenuSelectProcPtr) itsOld;
-
- theMenuSelect++;
-
- params->itsResult = (*oldMenuSelect)(params->itsStartPt);
- AbortTrap();
-
- theMenuSelect--;
- #endif
- }
-
- /******************************************************************************************/
-
- MenuKeyPatch::MenuKeyPatch()
- {
- GenericPatch::InitGenericPatch(_MenuKey, offsetof(MenuKeyParameters, itsResult));
- Install();
- }
-
- void MenuKeyPatch::Behavior()
- {
- reg MenuKeyParameters* params = (MenuKeyParameters*) itsFrame->parameters;
-
- if (params->itsKey == cSpace) {
- AbortTrap();
- params->itsResult = thePostEventPatch->FakeNavigation();
- }
- }
-
- /******************************************************************************************/
-
- PopupMenuSelectPatch::PopupMenuSelectPatch()
- {
- GenericPatch::InitGenericPatch(_PopUpMenuSelect, offsetof(PopupMenuSelectParameters, itsResult));
- Install();
- }
-
- void PopupMenuSelectPatch::Behavior()
- {
- reg PopupMenuSelectParameters* params = (PopupMenuSelectParameters*)itsFrame->parameters;
- reg PopupMenuSelectProcPtr oldMenuSelect = (PopupMenuSelectProcPtr) itsOld;
-
- theMenuSelect++;
-
- #if !__option(a4_globals)
- {
- long oldA5 = SetA5((long) itsFrame->ra5);
- #endif
-
- params->itsResult = (*oldMenuSelect)(params->itsMenuHandle, params->itsTop, params->itsLeft, params->itsItem);
-
- #if !__option(a4_globals)
- (void) SetA5(oldA5);
- }
- #endif
-
- AbortTrap();
-
- theMenuSelect--;
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
-
- void GetMousePatch::GetMousePatch()
- {
- GenericPatch::InitGenericPatch(_GetMouse, offsetof(GetMouseParameters, dummy));
- Install();
- Switch(ePatchOff);
- }
-
- void GetMousePatch::Behavior()
- {
- *(long*) &((GetMouseParameters*) (itsFrame->parameters))->itsPoint = 0;
- AbortTrap();
- }
-
- /******************************************************************************************/
-
- void EventAvailPatch::EventAvailPatch()
- {
- itsFromStart = false;
- GenericPatch::InitGenericPatch(_EventAvail, offsetof(EventAvailParameters, itsResult));
- Install();
- }
-
- // the number of real menus:
- // real menus in the menu list (that are in the menubar)
- // have a leftEdge > 0
- short EventAvailPatch::NumRealMenus()
- {
- reg short ctMenus = ((**theMenuList).itemOffset - 6) / sizeof(PerMenu);
- reg short ixMenu;
- reg PerMenu *p;
- reg short actualMenus = 0;
-
- p = (**theMenuList).permenu;
-
- for (ixMenu = 0; ixMenu <= ctMenus; ixMenu++, ++p) {
- if (p->itsLeftEdge > 0)
- ++actualMenus;
- }
-
- return actualMenus;
- }
-
- Boolean EventAvailPatch::FindMenuTitleLoc(Boolean next, Point *loc)
- {
- short ctMenus = NumRealMenus();
- short ixMenu;
- reg PerMenu *p;
-
- p = (**theMenuList).permenu;
-
- for (ixMenu = 0; ixMenu < ctMenus; ixMenu++, ++p) {
- if (p->itsHandle == nil)
- continue;
-
- if ((**p->itsHandle).menuID == (short) (MenuDisable >> 16))
- break;
- }
-
- if (ixMenu >= ctMenus) // how to handle error?
- return false;
-
- do {
- if (next) {
- if (ixMenu == (ctMenus - 1))
- ixMenu = 0;
- else
- ixMenu++;
- } else {
- if (ixMenu == 0)
- ixMenu = ctMenus - 1;
- else
- --ixMenu;
- }
-
- #ifdef DEBUG
- if (ixMenu < 0)
- DebugStr("\pixMenu < 0!!!");
- if (ixMenu >= ctMenus)
- DebugStr("\pixMenu > xx??!!");
- #endif
-
- p = &(**theMenuList).permenu[ixMenu];
- } while ((**p->itsHandle).menuID == 0xb020);
-
- CalcMenuSize(p->itsHandle); // note that p may have moved!
- p = &(**theMenuList).permenu[ixMenu];
-
- loc->v = MBarHeight >> 1;
- loc->h = p->itsLeftEdge + 8;
-
- return true;
- }
-
- Boolean EventAvailPatch::FindFirstMenuLoc(Point *loc)
- {
- reg PerMenu *p;
-
- p = (**theMenuList).permenu;
-
- CalcMenuSize(p->itsHandle); // note that p may have moved!
-
- p = (**theMenuList).permenu;
-
- loc->v = MBarHeight >> 1;
- loc->h = p->itsLeftEdge + 8;
-
- return true;
- }
-
- Boolean EventAvailPatch::FindLastMenuLoc(Point *loc)
- {
- short ctMenus = NumRealMenus();
- reg PerMenu *p;
-
- p = &(**theMenuList).permenu[ctMenus-1];
-
- CalcMenuSize(p->itsHandle); // note that p may have moved!
-
- p = &(**theMenuList).permenu[ctMenus-1];
-
- loc->v = MBarHeight >> 1;
- loc->h = p->itsLeftEdge + 8;
-
- return true;
- }
-
- short EventAvailPatch::FindMenuItemVPos(MenuHandle hMenu, short item)
- {
- reg short v = MBarHeight;
- short ctItems;
- Str255 s;
- short i;
-
- if (item == 0)
- return v - 3;
-
- v += 3;
-
- if (item == 1)
- return v;
-
- ctItems = CountMItems(hMenu);
-
- for (i = 1; i <= ctItems; i++) {
- if (i == item)
- return v;
-
- GetItem(hMenu, i, s);
-
- if (s[1] == '-')
- v += 13;
- else
- v += 18;
- }
-
- return v;
- }
-
-
- Boolean EventAvailPatch::FindMenuItemLoc(Boolean next, Point *loc)
- {
- Rect curMenuRect;
- short menuID = MenuDisable >> 16;
- short menuItem = MenuDisable & 0xffff;
- short ctItems;
- MenuHandle hMenu;
- short leftEdge;
-
- hMenu = FindInstalledMenu(menuID, &leftEdge);
-
- if (hMenu == nil)
- return false;
-
- ctItems = CountMItems(hMenu);
-
- if (menuItem == 1 && ctItems == 1) // special case, get off menu
- menuItem = 0;
- else {
- Str255 menuString;
- short tries;
-
- for (tries = 0; tries < ctItems; tries++) {
- if (next) {
- if (menuItem == ctItems)
- menuItem = 1;
- else
- ++menuItem;
- } else {
- if (menuItem <= 1)
- menuItem = ctItems;
- else
- --menuItem;
- }
- if ((((**hMenu).enableFlags & (1 << menuItem)) != 0)) { // item enabled?
- GetItem(hMenu, menuItem, menuString);
- if (menuString[1] != '-') // and not a -? break!
- break;
- }
- }
-
- if (tries == ctItems) {
- SysBeep(1);
- return false;
- }
- }
-
- loc->h = leftEdge + 8;
- loc->v = FindMenuItemVPos(hMenu, menuItem);
-
- return true;
- }
-
- static void DumpScreen()
- {
- #if 0
- Handle hProc = GetResource('FKEY', 3);
- if (hProc == nil) {
- SysBeep(1);
- return;
- }
- HNoPurge(hProc);
- asm {
- move.l hProc,a0
- move.l (a0),a0
- jsr (a0)
- }
- HPurge(hProc);
- #endif
- }
-
- void EventAvailPatch::Behavior()
- {
- Point loc;
- reg StickyEvent eve = itsEvent;
-
- itsEvent = eNullEvent; // consume
-
- switch (eve) {
- case eStart:
- break;
-
- case eStopBad:
- DumpScreen();
- theGetMousePatch->Switch(ePatchOn);
- itsEvent = eStopCleanup;
- break;
-
- case eStopGood:
- itsEvent = eStopCleanup;
- break;
-
- case eStopCleanup:
- theGetMousePatch->Switch(ePatchOff); // irregardless
- (void) PostEvent(mouseUp, 0);
-
- if (itsFromStart)
- SetMouse(itsInitialLoc);
-
- itsFromStart = false;
- break;
-
- case eNextMenu:
- case ePrevMenu:
- if (FindMenuTitleLoc(eve == eNextMenu, &loc))
- SetMouse(loc);
- break;
-
- case eFirstMenu:
- if (FindFirstMenuLoc(&loc))
- SetMouse(loc);
- break;
-
- case eLastMenu:
- if (FindLastMenuLoc(&loc))
- SetMouse(loc);
- break;
-
- case eNextItem:
- case ePrevItem:
- if (FindMenuItemLoc(eve == eNextItem, &loc))
- SetMouse(loc);
- break;
- }
- }
-
- void EventAvailPatch::SetupNavigation()
- {
- Point loc;
- itsEvent = eStart;
- itsFromStart = true;
- GetMouse(&itsInitialLoc);
- (void) FindFirstMenuLoc(&loc);
- SetMouse(loc);
- }
-
- void EventAvailPatch::SetStickyEvent(StickyEvent eve)
- {
- itsEvent = eve;
- }
-
- /******************************************************************************************/
-
- void Install()
- {
- theMenuSelect = 0;
-
- try {
- // if extension succeeds, show happy icon.
- SysEnvRec environment; // machine configuration.
-
- // find out what kind of machine this is.
- SysEnvirons(curSysEnvVers, &environment);
-
- thePostEventPatch = new PostEventPatch;
- theButtonPatch = new ButtonPatch;
- // new MenuSelectPatch;
- new MenuKeyPatch;
- new PopupMenuSelectPatch;
- theGetMousePatch = new GetMousePatch;
- theEventAvailPatch = new EventAvailPatch;
-
- if (environment.hasColorQD)
- theMenuBarRect.right = (**MainDevice).gdRect.right;
- else {
- RgnHandle r = GetGrayRgn();
- if (r == nil)
- DebugStr("\pnil grayrgn?");
- theMenuBarRect.right = (**r).rgnBBox.right - (**r).rgnBBox.left;
- }
-
- theMenuBarRect.left = 0;
- theMenuBarRect.top = 0;
- theMenuBarRect.bottom = 0x14;
-
- ShowIconFamily(128);
- } /* try */
-
- catch {
- // extension failed, show sad icon.
- ShowIconFamily(129);
- throw(theException);
- }
- }
-
- // called when system is shutdown.
-
- void Remove()
- {
- Patch::RemoveAll();
- }
-